package com.lwj.test.security;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.*;
import java.util.*;

public class DsmLoader extends URLClassLoader {
    static String path = (String) System.getProperty("user.dir");
    static CGen cgenObj = null;
    private HashMap sysfilelist = new HashMap();
    private ClassLoader parent = null;

    public static void main(final String[] args) throws Exception {
	DsmLoader.cgenObj = new CGen();
	String[] ar = new String[3];
	ar[0] = "run";
	ar[1] = DsmLoader.path;
	ar[2] = "down.DownEngine";
	final ClassLoader appLoader = new DsmLoader(
		DsmLoader.class.getClassLoader(), new File(ar[1]));
	Thread.currentThread().setContextClassLoader(appLoader);
	final Class app = appLoader.loadClass(ar[2]);
	final Method appmain = app.getMethod("main",
		new Class[] { String[].class });
	final String[] appargs = new String[ar.length - 3];
	System.arraycopy(ar, 3, appargs, 0, appargs.length);
	appmain.invoke(null, new Object[] { appargs });
    }

    public void initSysList() {
	try {
	    this.sysfilelist.put("down/Base64.class", "nulls");
	    this.sysfilelist.put("down/ColumnModel.class", "nulls");
	    this.sysfilelist.put("down/ColumnModelList.class", "nulls");
	    this.sysfilelist.put("down/DataTools.class", "nulls");
	    this.sysfilelist.put("down/DBControl.class", "nulls");
	    this.sysfilelist.put("down/DownEngine.class", "nulls");
	    this.sysfilelist.put("down/ElementModel.class", "nulls");
	    this.sysfilelist.put("down/ElementModelList.class", "nulls");
	    this.sysfilelist.put("down/GenClass.class", "nulls");
	    this.sysfilelist.put("down/General.class", "nulls");
	    this.sysfilelist.put("down/GeneralDownEngine.class", "nulls");
	    this.sysfilelist.put("down/Genxml.class", "nulls");
	    this.sysfilelist.put("down/Monitor.class", "nulls");
	    this.sysfilelist.put("down/OracleOperator.class", "nulls");
	    this.sysfilelist.put("down/SQLServerOperator.class", "nulls");
	    this.sysfilelist.put("down/SyncConfigure.class", "nulls");
	    this.sysfilelist.put("down/ProcessCenter.class", "nulls");
	    this.sysfilelist.put("down/ProcessEngine.class", "nulls");
	    this.sysfilelist.put("down/ProcessEngine$datFileter.class", "nulls");
	    this.sysfilelist.put("down/ProcessEngine$OpEngine.class", "nulls");
	    this.sysfilelist.put("down/ProcessEngine$ReadEngine.class", "nulls");
	    this.sysfilelist.put("down/XMLOperation.class", "nulls");
	    this.sysfilelist.put("down/XMLOperation$FileFilter.class", "nulls");
	    this.sysfilelist.put("down/DownListener.class", "nulls");
	    this.sysfilelist.put("down/dirFileFilter.class", "nulls");
	    this.sysfilelist.put("down/SQLServerPlatform.class", "nulls");
	    this.sysfilelist.put("down/OraclePlatform.class", "nulls");
	    this.sysfilelist.put("down/RecHandler.class", "nulls");
	} catch (Exception ex) {
	}

    }

    public DsmLoader(URL[] urls) {

	super(urls, ClassLoader.getSystemClassLoader());
	this.parent = ClassLoader.getSystemClassLoader();
    }

    public Class loadLibrary(String clazz) throws ClassNotFoundException {
	return loadClass(clazz, true);
    }

    public Class loadLibrary(String clazz, boolean resolve)
	    throws ClassNotFoundException {
	return loadClass(clazz, resolve);
    }

    public Class loadClass(final String name, final boolean resolve)
	    throws ClassNotFoundException {
	Class c = null;
	c = findLoadedClass(name);
	if (c == null) {
	    Class parentsVersion = null;
	    try {
		parentsVersion = getParent().loadClass(name);
		if (parentsVersion.getClassLoader() != getParent())
		    c = parentsVersion;
	    } catch (ClassNotFoundException ignore) {
	    } catch (ClassFormatError ignore) {
	    }

	    if (c == null) {
		try {
		    c = findClass(name);
		} catch (ClassNotFoundException ignore) {
		    c = parentsVersion;
		}
	    }
	}

	if (c == null)
	    throw new ClassNotFoundException(name);

	if (resolve)
	    resolveClass(c);

	return c;
    }

    protected Class findClass(final String name) throws ClassNotFoundException {
	Class cls = null;
	final String classResource = name.replace('.', '/') + ".class";
	final URL classURL = getResource(classResource);
	byte[] decryptedClassData = null;
	if (classURL != null) {
	    try {
		File f = new File(classURL.getFile());
		byte[] classBytes = DsmLoader.getFileByte(f);
		Object obj = this.sysfilelist.get(classResource);
		if (obj != null)
		    decryptedClassData = DsmLoader.cgenObj.getCipObj().doFinal(
			    classBytes);
		cls = defineClass(name, decryptedClassData, 0,
			decryptedClassData.length);
	    } catch (Exception ioe) {
		// cls=null;
		throw new ClassNotFoundException(name);
	    }
	}
	return cls;
    }

    private byte[] readFully(InputStream in) throws Exception {
	byte[] byteObj = null;
	((DataInputStream) in).readFully(byteObj);
	return byteObj;
    }

    public static byte[] getFileByte(File file) {
	byte[] data = null;
	int filesize = 0;
	try {
	    filesize = (int) file.length();
	    data = new byte[filesize];
	    DataInputStream in = new DataInputStream(new FileInputStream(file));
	    in.readFully(data);
	    in.close();
	} catch (Exception ex) {

	}
	return data;
    }

    private DsmLoader(final ClassLoader parent, final File classpath)
	    throws MalformedURLException {
	super(new URL[] { classpath.toURL() }, parent);
	this.initSysList();
	if (parent == null)
	    throw new IllegalArgumentException("EncryptedClassLoader"
		    + " requires a non-null delegation parent");
    }

    private Class findBaseClass(String name) throws ClassNotFoundException {

	if (this.parent == null) {
	    return findSystemClass(name);
	} else {
	    return this.parent.loadClass(name);
	}

    }
}
